import { Component, ElementRef, Input, OnInit, OnDestroy, NgZone, OnChanges, SimpleChanges, AfterViewInit, ContentChildren, QueryList, AfterContentInit, ContentChild, TemplateRef, ViewEncapsulation, ChangeDetectionStrategy, ChangeDetectorRef, ViewChild, DoCheck, ApplicationRef } from '@angular/core';

@Component({
    selector: 'ns-marquee',
    template: `
        <div class="ns-marquee-container" #container
             (mouseenter)="isHovered = true" 
             (mouseleave)="isHovered = false">
            <div class="ns-marquee-wrapper">
                <div class="ns-marquee-content" #content>
                    <ng-content></ng-content>
                </div>
                <div class="ns-marquee-clone" #clone *ngIf="needsScrolling"></div>
            </div>
            <div class="ns-marquee-fade-left" *ngIf="nsMarqueeFade"></div>
            <div class="ns-marquee-fade-right" *ngIf="nsMarqueeFade"></div>
        </div>
    `,
    styles: [`
        .ns-marquee-container {
            overflow: hidden;
            position: relative;
            width: 100%;
        }
        
        .ns-marquee-wrapper {
            position: relative;
        }
        
        .ns-marquee-content, .ns-marquee-clone {
            display: inline-block;
            white-space: nowrap;
        }
        
        .ns-marquee-fade-left {
            position: absolute;
            left: 0;
            top: 0;
            height: 100%;
            pointer-events: none;
            z-index: 2;
        }
        
        .ns-marquee-fade-right {
            position: absolute;
            right: 0;
            top: 0;
            height: 100%;
            pointer-events: none;
            z-index: 2;
        }
    `],
    encapsulation: ViewEncapsulation.None,
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class MarqueeComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit, AfterContentInit, DoCheck {
    @Input() nsMarqueeSpeed: number = 50; // 滚动速度，像素/秒
    @Input() nsMarqueePause: number = 1000; // 暂停时间（毫秒）
    @Input() nsMarqueeFade: boolean = true; // 是否启用边缘渐变效果
    @Input() nsMarqueeFadeWidth: number = 10; // 渐变宽度（像素）

    @ViewChild('container') containerRef!: ElementRef<HTMLDivElement>;
    @ViewChild('content') contentRef!: ElementRef<HTMLDivElement>;
    @ViewChild('clone') cloneRef?: ElementRef<HTMLDivElement>;

    private animationId: number | null = null;
    isHovered: boolean = false;
    needsScrolling: boolean = false;

    private fadeLeftElement: HTMLElement | null = null;
    private fadeRightElement: HTMLElement | null = null;

    // 用于内容变化检测
    private contentObserver: MutationObserver | null = null;
    private visibilityListener: () => void = () => {}; // 页面可见性监听器

    private lastContentHash: string = '';
    private lastCheckedContent: string = '';
    private checkCount: number = 0;
    private contentCheckTimer: any = null;
    private isDestroyed = false;
    private domChangeHandlerThrottled = false;

    constructor(
        private el: ElementRef,
        private zone: NgZone,
        private cdr: ChangeDetectorRef,
        private appRef: ApplicationRef
    ) { }

    ngOnInit() {
        // 不在此处启动定期检查，避免过早检测
        
        // 添加页面可见性变化监听
        this.setupVisibilityListener();
    }

    ngAfterContentInit() {
        // 初始化内容观察器，监听内容的变化
        setTimeout(() => this.setupContentObserver(), 100);
    }

    ngAfterViewInit() {
        setTimeout(() => {
            this.setupMarquee();

            // 存储初始内容信息
            if (this.contentRef) {
                this.lastContentHash = this.getContentHash();
                this.lastCheckedContent = this.contentRef.nativeElement.innerHTML;
                console.log('初始内容已存储');
            }

            // 设置稳定后的内容监控
            this.setupExtraChangeDetection();
        }, 100);
    }

    ngOnChanges(changes: SimpleChanges) {
        if (changes['nsMarquee'] && !changes['nsMarquee'].firstChange) {
            const newValue = changes['nsMarquee'].currentValue;
            const shouldEnable = newValue === true || newValue === '' || newValue === 'true';

            if (shouldEnable) {
                setTimeout(() => this.setupMarquee(), 0);
            } else {
                this.destroyMarquee();
            }
        }

        if (changes['nsMarqueeFade'] && !changes['nsMarqueeFade'].firstChange) {
            this.updateFadeEffect();
        }
    }

    ngOnDestroy() {
        this.isDestroyed = true;

        // 清理所有资源
        if (this.animationId !== null) {
            cancelAnimationFrame(this.animationId);
            this.animationId = null;
        }

        this.disconnectContentObserver();

        if (this.contentCheckTimer) {
            clearInterval(this.contentCheckTimer);
            this.contentCheckTimer = null;
        }
        
        // 移除页面可见性监听
        this.removeVisibilityListener();
    }

    ngDoCheck(): void {
        // 限制检查频率，保持性能的同时确保能检测到关键变化
        this.checkCount++;
        if (this.checkCount % 5 !== 0 || !this.contentRef) return; // 平衡性能和响应性

        const currentContent = this.contentRef.nativeElement.innerHTML;

        // 如果内容已初始化且发生变化
        if (this.lastCheckedContent && this.lastCheckedContent !== currentContent) {
            console.log('DoCheck检测到内容变化，重新启动滚动');

            // 更新跟踪的内容
            this.lastCheckedContent = currentContent;

            // 重新设置滚动
            this.restartMarquee();
        } else if (!this.lastCheckedContent) {
            // 首次初始化
            this.lastCheckedContent = currentContent;
        }
    }

    private setupContentObserver() {
        if (this.contentObserver || !this.contentRef || this.isDestroyed) return;

        try {
            // 创建观察选项 - 平衡检测能力和性能
            const config = {
                childList: true,
                subtree: true,
                characterData: true,
                attributes: false  // 不监视属性变化，通过ngDoCheck处理
            };

            // 创建新的观察器
            this.contentObserver = new MutationObserver((mutations) => {
                if (mutations.length > 0) {
                    console.log('MutationObserver检测到内容变化', mutations.length);

                    // 重启滚动
                    this.restartMarquee();

                    // 更新内容哈希
                    if (this.contentRef) {
                        this.lastCheckedContent = this.contentRef.nativeElement.innerHTML;
                    }
                }
            });

            // 开始观察
            this.contentObserver.observe(this.contentRef.nativeElement, config);
            console.log('内容观察器已启动');
        } catch (error) {
            console.error('设置内容观察器时出错:', error);
        }
    }

    private disconnectContentObserver() {
        if (this.contentObserver) {
            this.contentObserver.disconnect();
            this.contentObserver = null;
        }
    }

    private setupMarquee() {
        // 先清理之前的设置
        this.destroyMarquee();

        setTimeout(() => {
            if (!this.containerRef || !this.contentRef) return;

            const container = this.containerRef.nativeElement;
            const content = this.contentRef.nativeElement;

            // 确保可以获取正确的宽度
            content.style.display = 'inline-block';

            // 创建临时元素进行宽度测量
            const tempDiv = document.createElement('div');
            tempDiv.style.position = 'absolute';
            tempDiv.style.visibility = 'hidden';
            tempDiv.style.display = 'inline-block';
            tempDiv.style.whiteSpace = 'nowrap';

            // 复制内容到临时元素
            tempDiv.innerHTML = content.innerHTML;
            document.body.appendChild(tempDiv);

            // 获取内容真实宽度 - 使用多种方法确保准确
            let contentWidth = Math.max(
                content.scrollWidth,
                content.offsetWidth,
                tempDiv.offsetWidth
            );

            // 移除临时元素
            document.body.removeChild(tempDiv);

            const containerWidth = container.clientWidth;

            console.log('容器样式:', window.getComputedStyle(container).display);
            console.log('内容样式:', window.getComputedStyle(content).display);
            console.log('内容scrollWidth:', content.scrollWidth);
            console.log('内容offsetWidth:', content.offsetWidth);
            console.log('临时元素宽度:', tempDiv.offsetWidth);

            // 确保内容的所有子元素都被考虑进来
            let maxChildRight = 0;
            Array.from(content.children).forEach(child => {
                const childEl = child as HTMLElement;
                const childRight = childEl.offsetLeft + childEl.offsetWidth;
                maxChildRight = Math.max(maxChildRight, childRight);
            });

            // 如果最右边元素位置大于计算出的宽度，使用最右边元素位置
            if (maxChildRight > contentWidth) {
                contentWidth = maxChildRight;
                console.log('使用子元素计算的最大宽度:', contentWidth);
            }

            // 添加额外的安全边距
            contentWidth += 20;
            console.log('最终使用的内容宽度(含安全边距):', contentWidth);

            // 检查内容是否需要滚动
            if (contentWidth > containerWidth) {
                console.log('内容宽度大于容器，需要滚动');
                console.log('内容计算宽度:', contentWidth);
                console.log('容器宽度:', containerWidth);

                this.needsScrolling = true;
                this.cdr.detectChanges();

                // 添加渐变效果
                if (this.nsMarqueeFade) {
                    this.createFadeEffect();
                }

                // 开始动画
                this.startAnimation(contentWidth);
            } else {
                console.log('内容宽度不足，无需滚动');
                console.log('内容计算宽度:', contentWidth);
                console.log('容器宽度:', containerWidth);
                this.needsScrolling = false;
                this.cdr.detectChanges();
            }
        }, 100); // 增加延迟，确保DOM已完全渲染
    }

    private createFadeEffect() {
        if (!this.containerRef) return;

        // 获取渐变元素
        const fadeLeft = this.el.nativeElement.querySelector('.ns-marquee-fade-left') as HTMLElement;
        const fadeRight = this.el.nativeElement.querySelector('.ns-marquee-fade-right') as HTMLElement;

        if (!fadeLeft || !fadeRight) return;

        // 获取计算后的背景色
        const computedStyle = window.getComputedStyle(this.containerRef.nativeElement);
        let bgColor = computedStyle.backgroundColor;

        // 如果背景色是透明的，使用白色
        if (bgColor === 'transparent' || bgColor === 'rgba(0, 0, 0, 0)') {
            bgColor = 'white';
        }

        // 设置渐变样式
        fadeLeft.style.width = `${this.nsMarqueeFadeWidth}px`;
        fadeLeft.style.background = `linear-gradient(to right, ${bgColor}, rgba(255, 255, 255, 0))`;

        fadeRight.style.width = `${this.nsMarqueeFadeWidth}px`;
        fadeRight.style.background = `linear-gradient(to left, ${bgColor}, rgba(255, 255, 255, 0))`;

        this.fadeLeftElement = fadeLeft;
        this.fadeRightElement = fadeRight;

        console.log('创建渐变效果，背景色:', bgColor);
    }

    private updateFadeEffect() {
        if (this.nsMarqueeFade) {
            this.cdr.detectChanges();
            this.createFadeEffect();
        } else {
            this.cdr.detectChanges();
        }
    }

    private cloneContent() {
        if (!this.contentRef || !this.cloneRef) return;

        const content = this.contentRef.nativeElement;
        const clone = this.cloneRef.nativeElement;

        // 清空克隆元素
        clone.innerHTML = '';

        // 深度克隆原始内容，包括事件监听器
        const clonedContent = content.cloneNode(true) as HTMLElement;

        // 取出克隆内容的子节点并添加到克隆容器中
        while (clonedContent.firstChild) {
            clone.appendChild(clonedContent.firstChild);
        }

        console.log('内容已重新克隆');
    }

    private startAnimation(contentWidth: number) {
        if (!this.contentRef || !this.cloneRef) return;

        const content = this.contentRef.nativeElement;
        const clone = this.cloneRef.nativeElement;
        const wrapper = content.parentElement;

        // 如果父元素不存在，则退出
        if (!wrapper) {
            console.error('找不到包装器元素，无法执行滚动动画');
            return;
        }

        // 重置位置和样式
        content.style.transform = '';
        clone.style.transform = '';
        wrapper.style.transform = '';

        // 克隆内容
        this.cloneContent();

        console.log('动画开始，内容宽度:', contentWidth);

        // 如果内容宽度为0，可能是布局还没完成，稍后再试
        if (contentWidth === 0) {
            setTimeout(() => this.setupMarquee(), 200);
            return;
        }

        const containerWidth = this.containerRef.nativeElement.clientWidth;

        // 设置内容区域宽度
        content.style.width = contentWidth + 'px';
        clone.style.width = contentWidth + 'px';

        // 使用绝对定位
        wrapper.style.position = 'relative';
        content.style.position = 'absolute';
        content.style.left = '0';
        content.style.top = '0';

        clone.style.position = 'absolute';
        clone.style.left = contentWidth + 'px';
        clone.style.top = '0';

        // 设置包装器宽度
        wrapper.style.width = (contentWidth * 2) + 'px';
        wrapper.style.height = content.offsetHeight + 'px';

        let startTime: number | null = null;
        let isPaused = false;
        let pauseEndTime = 0;
        let position = 0;
        let justCompleted = false;

        const animate = (timestamp: number) => {
            if (!startTime) startTime = timestamp;

            // 处理鼠标悬停
            if (this.isHovered) {
                startTime = timestamp;
                this.animationId = requestAnimationFrame(animate);
                return;
            }

            // 暂停处理
            if (isPaused) {
                if (timestamp < pauseEndTime) {
                    startTime = timestamp;
                    this.animationId = requestAnimationFrame(animate);
                    return;
                } else {
                    // 暂停结束
                    isPaused = false;
                }
            }

            const elapsed = timestamp - startTime;
            const pixelsToMove = (elapsed * this.nsMarqueeSpeed / 1000);

            // 更新位置
            position -= pixelsToMove;

            // 当第一条内容完全滚动出去后，重置位置并暂停
            if (Math.abs(position) >= contentWidth && !justCompleted) {
                position = position + contentWidth;

                // 每次循环完成后刷新克隆内容
                this.cloneContent();

                // 如果设置了暂停时间，则暂停
                if (this.nsMarqueePause > 0) {
                    isPaused = true;
                    pauseEndTime = timestamp + this.nsMarqueePause;
                }

                justCompleted = true;
            } else if (Math.abs(position) < contentWidth * 0.9) {
                // 重置完成标志
                justCompleted = false;
            }

            // 设置包装器的位置
            wrapper.style.transform = `translateX(${position}px)`;

            startTime = timestamp;
            this.animationId = requestAnimationFrame(animate);
        };

        this.zone.runOutsideAngular(() => {
            this.animationId = requestAnimationFrame(animate);
        });
    }

    private destroyMarquee() {
        // 取消动画帧
        if (this.animationId !== null) {
            cancelAnimationFrame(this.animationId);
            this.animationId = null;
        }

        // 重置滚动状态
        this.needsScrolling = false;

        // 重置包装器和内容样式
        if (this.contentRef) {
            const content = this.contentRef.nativeElement;
            // 清除内容的所有样式
            content.style.transform = '';
            content.style.width = '';
            content.style.position = '';
            content.style.left = '';
            content.style.top = '';

            // 清除包装器的所有样式
            if (content.parentElement) {
                content.parentElement.style.transform = '';
                content.parentElement.style.width = '';
                content.parentElement.style.position = '';
                content.parentElement.style.height = '';
            }

            // 清空克隆元素并重置样式
            if (this.cloneRef) {
                const clone = this.cloneRef.nativeElement;
                clone.innerHTML = '';
                clone.style.transform = '';
                clone.style.position = '';
                clone.style.left = '';
                clone.style.top = '';
                clone.style.width = '';
            }
        }

        // 移除渐变效果元素
        this.fadeLeftElement = null;
        this.fadeRightElement = null;

        // 强制更新视图
        this.cdr.markForCheck();
        this.cdr.detectChanges();

        console.log('滚动已完全重置');
    }

    private restartMarquee() {
        // 先停止当前滚动
        if (this.animationId !== null) {
            cancelAnimationFrame(this.animationId);
            this.animationId = null;
        }

        // 在下一个宏任务中重启，确保DOM已更新
        setTimeout(() => {
            // 只有在组件仍然存在时才重启
            if (!this.isDestroyed) {
                this.setupMarquee();
            }
        }, 50); // 恢复原来的延迟
    }

    private getContentHash(): string {
        if (!this.contentRef) return '';
        const content = this.contentRef.nativeElement;
        // 简单地使用内容的HTML作为哈希
        return content.innerHTML;
    }

    private setupExtraChangeDetection() {
        // 针对嵌套ngIf变化的额外检测
        this.zone.runOutsideAngular(() => {
            // 在每次稳定之后，检查内容是否有变化
            const stableSubscription = this.appRef.isStable.subscribe(isStable => {
                if (isStable && this.contentRef && !this.isDestroyed) {
                    const currentHtml = this.contentRef.nativeElement.innerHTML;
                    if (this.lastContentHash && this.lastContentHash !== currentHtml) {
                        console.log('应用稳定时检测到内容变化');
                        this.lastContentHash = currentHtml;

                        // 在变更检测周期内执行重启
                        this.zone.run(() => {
                            this.restartMarquee();
                        });
                    } else if (!this.lastContentHash) {
                        this.lastContentHash = currentHtml;
                    }
                }
            });

            // 在组件销毁时取消订阅
            const originalOnDestroy = this.ngOnDestroy;
            this.ngOnDestroy = () => {
                stableSubscription.unsubscribe();
                originalOnDestroy.call(this);
            };
        });
    }

    private setupVisibilityListener() {
        // 在Angular区域外监听visibility change事件
        this.zone.runOutsideAngular(() => {
            this.visibilityListener = () => {
                if (document.visibilityState === 'visible' && !this.isDestroyed) {
                    console.log('页面恢复可见，重启跑马灯');
                    
                    // 在Angular区域内执行重启操作
                    this.zone.run(() => {
                        if (this.contentRef) {
                            this.restartMarquee();
                        }
                    });
                }
            };
            
            document.addEventListener('visibilitychange', this.visibilityListener);
        });
    }
    
    private removeVisibilityListener() {
        if (this.visibilityListener) {
            document.removeEventListener('visibilitychange', this.visibilityListener);
        }
    }
} 